package com.atguigu.service.impl;

import com.atguigu.constant.RedisConst;
import com.atguigu.entity.CartInfo;
import com.atguigu.entity.SkuInfo;
import com.atguigu.feign.ProductFeignClient;
import com.atguigu.mapper.CartInfoMapper;
import com.atguigu.service.AsyncCartInfoService;
import com.atguigu.service.CartInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车表 用户登录系统时更新冗余 服务实现类
 * </p>
 *
 * @author hachimen
 * @since 2021-09-04
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {

    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AsyncCartInfoService asyncCartInfoService;

    @Override
    public void addToCart(Long skuId, Integer skuNum, String userId) {
        //查询购物车信息，有则增加数量，无则添加item
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId);
        wrapper.eq("sku_id",skuId);
        CartInfo cartInfo = baseMapper.selectOne(wrapper);
        if(cartInfo != null){
            //有
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            //baseMapper.updateById(cartInfo);
            asyncCartInfoService.updateCartInfo(cartInfo);
        }else {
            //无
            cartInfo = new CartInfo();
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setCartPrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setSkuNum(skuNum);
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setUserId(userId);
            cartInfo.setIsChecked(1);
            //baseMapper.insert(cartInfo);
            asyncCartInfoService.saveCartInfo(cartInfo);
        }
        String cartKey = getCartKey(userId);
        redisTemplate.boundHashOps(cartKey).put(skuId.toString(),cartInfo);
        //先存数据库，再存redis
        setCartKeyExpire(cartKey);
        //设置过期时间
    }
    //设置redis过期时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey,RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        List<CartInfo> cartList = new ArrayList<>();
        //未登录时查询数据库
        if(StringUtils.isEmpty(userId)){
            //未登录
            cartList = queryDBCartListToRedis(userTempId);
        }
        if(!StringUtils.isEmpty(userId)){
            //登录时，如果有未登录的购物车信息，则进行合并
            List<CartInfo> cartTempDBList = queryDBCartListToRedis(userTempId);
            if(!CollectionUtils.isEmpty(cartTempDBList)){
                cartList = mergeCartList(cartTempDBList,userId);//合并
                deleteNoLoginCartInfoList(userTempId);//删除
            }
            if(CollectionUtils.isEmpty(cartTempDBList)||StringUtils.isEmpty(userTempId)){
                //无未登录购物车信息
                cartList = queryDBCartListToRedis(userId);
            }
        }
        return cartList;
    }
        //未登录购物车合并
    private List<CartInfo> mergeCartList(List<CartInfo> cartTempDBList, String userId) {
        List<CartInfo> cartDBList = queryDBCartListToRedis(userId);
        Map<Long, CartInfo> cartDBMap = cartDBList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));

        for (CartInfo cartTempInfo : cartTempDBList) {
            CartInfo cartInfo = cartDBMap.get(cartTempInfo.getSkuId());
            if(cartInfo!=null){
                //未登录购物车数据不唯一  获取与未登录数据对应的购物车商品数据，增加数量，之后删除未登录购物车数据
                cartInfo.setSkuNum(cartTempInfo.getSkuNum()+cartInfo.getSkuNum());//获得合并后的cartInfo
                if(cartTempInfo.getIsChecked()==1){
                    cartInfo.setIsChecked(1);
                }
                baseMapper.updateById(cartInfo);//修改

            }else{
                //未登录购物车数据唯一  直接修改userId
                cartTempInfo.setUserId(userId);
                baseMapper.updateById(cartTempInfo);//修改

            }
        }
        return queryDBCartListToRedis(userId);
    }
    //获取用户购物车列表
    private List<CartInfo> getUserCartList(String oneOfUserId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        //如果临时用户id也为空
        if (StringUtils.isEmpty(oneOfUserId)) {
            return cartInfoList;
        }
        //从数据库里面查询数据放到redis
        cartInfoList = queryDBCartListToRedis(oneOfUserId);
        return cartInfoList;
    }

    //通过一个UserID从数据库中查询购物车列表并更新缓存
    @Override
    public List<CartInfo> queryDBCartListToRedis(String oneOfUserId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",oneOfUserId);
        List<CartInfo> DBCartList = baseMapper.selectList(wrapper);
        if(CollectionUtils.isEmpty(DBCartList)){
            return DBCartList;
        }
        String cartKey = getCartKey(oneOfUserId);
        Map<String, CartInfo> cartInfoMap = new HashMap<>();
        /*Map<Long, CartInfo> cartInfoMap = DBCartList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo ->
        {return cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()))}));
        redisTemplate.opsForHash().putAll(getCartKey(oneOfUserId),cartInfoMap);*/
        for (CartInfo cartInfo : DBCartList) {
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            cartInfoMap.put(cartInfo.getSkuId().toString(),cartInfo);
        }
        redisTemplate.opsForHash().putAll(cartKey,cartInfoMap);
        setCartKeyExpire(cartKey);
        return DBCartList;
    }

    @Override
    public void checkCart(String userId, Long skuId, Integer isChecked) {
        asyncCartInfoService.checkCart(userId,isChecked,skuId);
        String cartKey = getCartKey(userId);
        BoundHashOperations operations = redisTemplate.boundHashOps(cartKey);
        Boolean aBoolean = operations.hasKey(skuId.toString());
        if (aBoolean!=null&&aBoolean){
            CartInfo redisCartInfo = (CartInfo) operations.get(skuId.toString());
            redisCartInfo.setIsChecked(isChecked);
            operations.put(skuId.toString(),redisCartInfo);
            setCartKeyExpire(cartKey);
        }
    }

    @Override
    public void deleteCartInfo(String userId, Long skuId) {
        asyncCartInfoService.deleteCartInfo(userId,skuId);
        String cartKey = getCartKey(userId);
        BoundHashOperations operations = redisTemplate.boundHashOps(cartKey);
        Boolean aBoolean = operations.hasKey(skuId.toString());
        if(aBoolean!=null&&aBoolean){
            operations.delete(skuId.toString());
        }
    }

    @Override
    public List<CartInfo> getSelectedProduct(String userId) {
        List<CartInfo> retCartInfoList = new ArrayList<>();
        String cartKey = getCartKey(userId);
        List<CartInfo> redisCartInfoList = redisTemplate.opsForHash().values(cartKey);
        if(!CollectionUtils.isEmpty(redisCartInfoList)){
            for (CartInfo cartInfo : redisCartInfoList) {
                if (cartInfo.getIsChecked() == 1){
                    retCartInfoList.add(cartInfo);
                }
            }
        }
        return retCartInfoList;
    }

    //通过userId获取redisKey
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
    }

    //删除未登录的购物车信息
    private void deleteNoLoginCartInfoList(String userTempId){
        asyncCartInfoService.deleteCartInfo(userTempId, null);
        String cartKey = getCartKey(userTempId);
        Boolean aBoolean = redisTemplate.hasKey(cartKey);
        if (aBoolean!=null&&aBoolean){
            redisTemplate.delete(cartKey);
        }
    }
}
